package com.clever.auth.config;

import com.clever.auth.shiro.LoginRealms;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.crypto.hash.Sha256Hash;
import org.apache.shiro.mgt.DefaultSecurityManager;
import org.apache.shiro.realm.Realm;
import org.apache.shiro.session.mgt.SessionManager;
import org.apache.shiro.spring.web.config.DefaultShiroFilterChainDefinition;
import org.apache.shiro.spring.web.config.ShiroFilterChainDefinition;
import org.apache.shiro.util.ThreadContext;
import org.apache.shiro.web.session.mgt.DefaultWebSessionManager;
import org.crazycake.shiro.RedisCacheManager;
import org.crazycake.shiro.RedisSessionDAO;
import org.springframework.aop.framework.autoproxy.DefaultAdvisorAutoProxyCreator;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.annotation.Primary;

import javax.annotation.Resource;

/**
 * @author ChenWang
 * @date 2020/12/14 18:51
 * @since JDK 1.8
 *
 *
 *
 * 初始化 WebSecurityManager
 * 注册  LoginRealms
 * <p>
 * 权限 必须认证才能正常访问  前端 客服端
 * 认证通过之后需要权限才能访问或者操作
 */
@Configuration
public class ShiroAuthConfig {
    @Resource
    RedisSessionDAO redisSessionDAO;
    @Resource
    RedisCacheManager redisCacheManager;
    public static final int SHA_256_ITERATION_NUM = 100;

    @Bean
    @Primary
    public Realm realm(HashedCredentialsMatcher hashedCredentialsMatcher) {
        LoginRealms loginRealms = new LoginRealms();
        // 在自定义的realms中注册
        loginRealms.setCredentialsMatcher(hashedCredentialsMatcher);
        return loginRealms;
    }

    /**
     * 安全管理配置
     * ThreadContext.bind(manager);
     * manager.setReal(realm());//这个就不需要传入参数 realm了,不过现在一般还是通过传参来注入
     * @param sessionManager
     * @param realm
     * @return
     */
    @Bean("securityManager")
    public DefaultSecurityManager securityManager(SessionManager sessionManager, Realm realm) {
        DefaultSecurityManager manager = new DefaultSecurityManager();
        // 绑定上下文
        // springboot   跟 shiro版本兼容的
        ThreadContext.bind(manager);
        // 注册 自定义realm
        manager.setRealm(realm);
        // 注册 自定义会话管理
        manager.setSessionManager(sessionManager);
        // 设置 redis缓存管理
        manager.setCacheManager(redisCacheManager);
        return manager;

    }

    /**
     *  过滤器
     *  1. 放行的路径
     *  2. 需要登录的路径
     * @return
     */
    @Bean("shiroFilter")
    public ShiroFilterChainDefinition shiroFilterChainDefinition() {
        DefaultShiroFilterChainDefinition definition = new DefaultShiroFilterChainDefinition();
        // 需要放行的路径
        definition.addPathDefinition("/login", "anon");
        definition.addPathDefinition("/register", "anon");
        definition.addPathDefinition("/druid/**", "anon");
        // 配置用户登出
        definition.addPathDefinition("/logout", "logout");
        // 需要登录的路径
        definition.addPathDefinition("/admin/**", "authc");
        definition.addPathDefinition("/**", "authc");
        return definition;
    }

    @Bean("sessionManager")
    public SessionManager sessionManager() {
        DefaultWebSessionManager defaultWebSessionManager = new DefaultWebSessionManager();
        //开启删除无效信息
        defaultWebSessionManager.setDeleteInvalidSessions(true);
        //开启定时任务--》定期检测过期信息
        defaultWebSessionManager.setSessionValidationSchedulerEnabled(true);
        defaultWebSessionManager.setSessionValidationInterval(60 * 60 * 1000);
        // 取消url后面的jsessionid
        defaultWebSessionManager.setSessionIdUrlRewritingEnabled(false);
        //设置全局session的过期时间
        defaultWebSessionManager.setGlobalSessionTimeout(7*24*60*60);
        //设置session的DAO层的操作处理
        defaultWebSessionManager.setSessionDAO(redisSessionDAO);
        return  defaultWebSessionManager;
    }


    /**
     * 设置加密算法
     *
     * @return HashedCredentialsMatcher 加密算法的封装类
     */
    @Bean
    @Primary
    public HashedCredentialsMatcher hashedCredentialsMatcher() {
        HashedCredentialsMatcher hashedCredentialsMatcher = new HashedCredentialsMatcher();
        // SHA-256 加密算法
        hashedCredentialsMatcher.setHashAlgorithmName(Sha256Hash.ALGORITHM_NAME);
        // 迭代次数
        hashedCredentialsMatcher.setHashIterations(SHA_256_ITERATION_NUM);
        // 转成16进制的数据
        hashedCredentialsMatcher.setStoredCredentialsHexEncoded(true);

        return hashedCredentialsMatcher;
    }


    /**
     *  如果出现了不能注册代理的情况，那么就需要导入下面这个包
     * @return
     */
    @Bean
    public DefaultAdvisorAutoProxyCreator defaultAdvisorAutoProxyCreator(){
        DefaultAdvisorAutoProxyCreator greator = new DefaultAdvisorAutoProxyCreator();
        greator.setProxyTargetClass(true);
        return greator;
    }
}
